#!/usr/bin/python
#-*-coding UTF-8 -*-
#filename update_net.py
import sys
import os
import re
import struct
import socket
import threading
#from socket import *
import time
reload(sys)
sys.setdefaultencoding('utf8')

SeriaHandle = ''

POLYNOMIAL = 0x1021
INITIAL_REMAINDER = 0xFFFF
FINAL_XOR_VALUE = 0x0000
WIDTH = 16
TOPBIT = (1 << (WIDTH - 1))
crcTable = {}
stream = []

def debugPackPrint(style,data):
    data = struct.unpack(style*len(data),data)
    print ' 0x'.join('%02x' % x for x in data)

def crcInit():
	SHIFT = WIDTH - 8
	for step in range(0, 256):
		remainder = step << SHIFT
		for bit in range(8, 0, -1):
			if remainder & TOPBIT:
				remainder = ((remainder << 1) & 0xFFFF) ^ 0x1021
			else:
				remainder = remainder << 1
		crcTable[step] = remainder
 
def crcFast(data):
    remainder = 0xFFFF
    for n in range(len(data)):
        datan = data[n] ^ (remainder >> (WIDTH - 8))
        remainder = crcTable[datan] ^ ((remainder << 8)&0xFFFF)  
    remainder = remainder & 0xffff    
    return crcCalc(data) 

def crcCalc(data):
    crc = 0
    for n in range(len(data)):
        i = 0x80
        while i :
            if crc & 0x8000:
                crc = crc * 2
                crc = crc ^ 0x1021
            else:
                crc = crc * 2
            if data[n]&i :
                crc = crc ^ 0x1021
            crc = crc & 0xffff
            i = i >> 1
    crc = crc & 0xffff
    return crc

def parseconfig(line,config,configip):
    ps = re.search("(\w+)\s+=\s+(\d+\.\d+\.\d+\.\d+\s*:\s*\d+)",line)
    if ps:
        configip.append(ps.groups()[1])
        return
    ps = re.search("(\w+)\s+=\s+([\w+\.]+)",line)
    if ps:
        config[ps.groups()[0]] = ps.groups()[1]
        return

        
def ReadConfig(path,config,configip):
    file = open(path,'rb')
    for line in file.readlines():
        if line.startswith(';') :
            continue
        ps = re.match('\[(\w+)\]',line)
        if ps :
            print ps.group()[0]
            continue
        #print line
        parseconfig(line,config,configip)
    file.close()

def formatStrToByte(target):
    buff = []
    for i in range(len(target)):
        buff.append(ord(target[i]))
    return buff

def getIModemcrc(buff):
    crc = []
    crc16 = crcCalc(buff)
    crc.append((crc16&0xff00)>>8)
    crc.append(crc16&0x00ff)
    return crc
    
def getIModemHead(bufflen,sn):
    head = []
    if bufflen == 128:
        head.append(0x01)
    else:
        head.append(0x02)
    head.append(sn&0xff)
    head.append((~sn)&0xff)
    return head

def getIModemStartFram(filename,sn):
    head = getIModemHead(128,sn)
    print 'head is ',head
    body = formatStrToByte(filename)
    body.append(0)
    filesize = os.path.getsize(filename)
    body += formatStrToByte('%d' % filesize)
    body.append(0x20)
    body.append(0)
    body += [0]*(128 - len(body))
    crc = getIModemcrc(body)
    return head + body + crc

def getIModemDataFram(databuff,sn):
    bufflen = 0
    datalen = len(databuff)
    if datalen <= 128:
        bufflen = 128
    elif datalen <= 1024:
        bufflen = 1024
    else:
        print 'getIModemDataFram datalen error'
    head = getIModemHead(bufflen,sn)
    body = list(struct.unpack('B'*len(databuff),databuff))
    if bufflen > len(body):
        body += [0x1a] * (bufflen - len(body))
    crc = getIModemcrc(body)
    return head + body + crc

def getIModemStopFram():
    head = getIModemHead(128,0)
    body = [0]*128
    crc = getIModemcrc(body)
    return head + body + crc

def getIModemStream(path):
    sn = 0
    flow= []
    filesize = os.path.getsize(path)
    print "filename %s filesize %d" %(path,filesize)
    file = open(path,'rb')
    tempdata = getIModemStartFram(path, sn)
    print tempdata
    sn += 1
    tempdata = struct.pack('B'*len(tempdata),*tempdata)
    flow.append(tempdata)
    print flow
    while filesize >1024:
        buff = file.read(1024)
        filesize = filesize -1024
        tempdata = getIModemDataFram(buff,sn)
        sn += 1
        tempdata = struct.pack('B'*len(tempdata),*tempdata)
        flow.append(tempdata)
    buff = file.read(filesize)
    tempdata = getIModemDataFram(buff,sn)
    sn += 1
    tempdata = struct.pack('B'*len(tempdata),*tempdata)
    flow.append(tempdata)    
    file.close()
    tempdata = [0x04]
    tempdata = struct.pack('B'*len(tempdata),*tempdata)
    flow.append(tempdata)
    flow.append(tempdata)
    tempdata = getIModemStopFram()
    tempdata = struct.pack('B'*len(tempdata),*tempdata)
    flow.append(tempdata)
    return flow
def sendNetUpdateCMD():
    ip = '192.168.0.8'
    port = 1025
    addr = (ip,port)
    cmd = (0xaa,0x09,0x00,0xfe,0x40,0x00,0x02,0x00,0x55)
    print cmd
    client = socket.socket()
    client.connect(addr)
    cmd_hex = struct.pack('B'*len(cmd),*cmd)
    #cmd = ''.join(map(str,cmd))
    print cmd_hex
    #client.send(cmd_hex)
    client.close()

lock = threading.Lock()

def sendNetIModem(datastream,ip,port,config={}):
    if len(datastream) < 5:
        print "data len error"
#    datastream.insert(0,'2')
    #ip = '192.168.0.8'
    #port = 1024
    addr = (ip,port)
    client = socket.socket()
    client.connect(addr)
    if config['isjumptoboot'] == 'yes':
        cmd = (0xaa,0x09,0x00,0xfe,0x40,0x00,0x02,0x00,0x55)
        print cmd
        cmd_hex = struct.pack('B'*len(cmd),*cmd)
        client.send(cmd_hex)
    time.sleep(1)
    client.send(datastream[0])
    debugPackPrint('B',datastream[0])
    print 'sleep(1)'
    time.sleep(1)
    client.send(datastream[1])
    debugPackPrint('B',datastream[1])
    print 'sleep(8)'
    time.sleep(4)
    for n in range(2,len(datastream)):
        lock.acquire()
        client.send(datastream[n])
        lock.release()
        debugPackPrint('B',datastream[n])
        print 'sleep(2)'
        time.sleep(2)
    
    client.close()

def thread_func(arg):
    global stream
    sock=arg.split(':')
    ip = sock[0]
    port = int(sock[1])
    print ip
    print port
    sendNetIModem(stream,ip,port)
    
if __name__ == "__main__":
    global stream
    config = {}
    configip = []
    config_path = sys.argv[1]
    print config_path
    crcInit()
    print crcTable
    ReadConfig(config_path, config,configip)
    print config
    print configip
    stream = getIModemStream(config['filename'])
    stream.insert(0,'2')
    time.sleep(2)
    for ip in configip:
        #new = threading.Thread(target=thread_func,args=(ip,))
        #new.start()
        sock=ip.split(':')
        ipaddr = sock[0]
        port = int(sock[1])
        sendNetIModem(stream,ipaddr,port,config)
    